using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xzipit.GameObjects;
using Microsoft.Xna.Framework;
using FlatRedBall;
using Microsoft.Xna.Framework.Media;
using System.IO;
using System.IO.IsolatedStorage;
using Xzipit.Utilities.Touch;

namespace Xzipit.Utilities
{
    public class Level
    {
        #region Fields
        private List<Obstacle> _obstacles;
        private Zipper _zipper;

        private Sprite _background;

        private List<double> _targetTimes;

        private string _levelName;
        private string _levelDesc;

        private bool _tutorial;

        #endregion

        #region Properties
        public bool Restarting
        {
            get;
            set;
        }

        public bool IsTutorial
        {
            get { return _tutorial; }
        }

        public List<double> TargetTimes
        {
            get { return _targetTimes; }
        }

        public string LevelName
        {
            get { return _levelName; }
        }

        public string LevelDesc
        {
            get { return _levelDesc; }
        }

        public bool IsZipperJammed
        {
            get { return _zipper.State == Zipper.ZipperState.Jammed; }
        }

        public bool HasWon
        {
            get
            {
                if (_zipper.IsAtEnd)
                {
                    foreach (Obstacle o in _obstacles)
                    {
                        o.Enabled = false;
                    }
                }
                return _zipper.IsAtEnd; }
        }

        #endregion

        #region Constructors
        public Level()
        {
            LoadLevel();
            Restarting = false;
        }

        public Level(int worldNum, int levelNum)
        {
            LoadLevel(worldNum, levelNum);
            Restarting = false;
        }

        #endregion

        #region Methods

        #region Initialization

        private void LoadLevel()
        {
            LoadLevel(GameProperties.SelectedWorld, GameProperties.SelectedLevel);
        }

        private void LoadLevel(int worldNum, int levelNum)
        {
            IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
            string path = GetLevelPath(worldNum, levelNum);

            StreamReader read = new StreamReader(TitleContainer.OpenStream(path));

            List<Vector3> track = new List<Vector3>();
            _targetTimes = new List<double>();
            _obstacles = new List<Obstacle>();


            while (!read.EndOfStream)
            {
                string line = read.ReadLine();
                string[] splitLine = line.Split(' ');
                if (splitLine[0].Equals("ln"))
                {
                    // read from after the space to the end of the line.
                    _levelName = line.Substring(3);
                }
                else if (splitLine[0].Equals("ld"))
                {
                    // read from after the space to the end of the line for description
                    _levelDesc = line.Substring(3);
                }
                else if (splitLine[0].Equals("t"))
                {
                    // only add gold, silver and bronze.
                    if (_targetTimes.Count < 3)
                    {
                        _targetTimes.Add(double.Parse(splitLine[2]));
                    }
                }
                else if (splitLine[0].Equals("bg"))
                {
                    SetBG(int.Parse(splitLine[1]));
                }
                else if (splitLine[0].Equals("n"))
                {
                    track.Add(new Vector3(float.Parse(splitLine[1]), float.Parse(splitLine[2]), 0.0f));
                }
                else if (splitLine[0].Equals("b"))
                {
                    Button b = new Button("Global", float.Parse(splitLine[1]),
                        float.Parse(splitLine[2]), int.Parse(splitLine[3]), float.Parse(splitLine[4]),
                        float.Parse(splitLine[5]));
                    b.Alpha = 0.0f;
                    _obstacles.Add(b);
                }
                else if (splitLine[0].Equals("v"))
                {
                    Velcro v = new Velcro("Global", float.Parse(splitLine[1]),
                        float.Parse(splitLine[2]), int.Parse(splitLine[3]), float.Parse(splitLine[4]));
                    v.Alpha = 0.0f;
                    _obstacles.Add(v);
                }
                else if (splitLine[0].Equals("o"))
                {
                    Necklace n = new Necklace("Global", float.Parse(splitLine[1]),
                        float.Parse(splitLine[2]), new Vector3(float.Parse(splitLine[4]),
                        float.Parse(splitLine[5]), 0.0f));
                    n.Alpha = 0.0f;
                    _obstacles.Add(n);
                }
                else if (splitLine[0].Equals("k"))
                {
                    Buckle b = new Buckle("Global", float.Parse(splitLine[1]),
                        float.Parse(splitLine[2]), int.Parse(splitLine[3]), float.Parse(splitLine[4]),
                        int.Parse(splitLine[5]));
                    b.Alpha = 0.0f;
                    _obstacles.Add(b);
                }
                else if (splitLine[0].Equals("tut"))
                {
                    if (splitLine[1].Equals("y"))
                        _tutorial = true;
                    else
                        _tutorial = false;
                }
            }

            read.Close();

            foreach (Obstacle o in _obstacles)
            {
                o.SetTooltip(_tutorial);
            }

            _zipper = new Zipper("Global", track);
            _zipper.Alpha = 0.0f;
        }

        #endregion

        #region Update
        public void Activity(double elapsedTime)
        {
            TouchManager.Update(_zipper.LastDrag, elapsedTime);
            _zipper.Activity();

            // Runs the Activity method for all obstacles.
            foreach (Obstacle o in _obstacles)
            {
                o.Activity(_zipper.LastDrag, elapsedTime);

                if (o is Necklace)
                {
                    foreach (Obstacle n in _obstacles)
                    {
                        if (n is Necklace)
                        {
                            ((Necklace)o).CollideWithNecklace((Necklace)n);
                        }
                    }
                }

                if (o is Blocker)
                {
                    o.X = _zipper.X;
                }

                if ((o.Enabled)
                    && (_zipper.State != Zipper.ZipperState.Jammed)
                    && (_zipper.Collision.CollideAgainst(o.Collision)))
                {
                    _zipper.State = Zipper.ZipperState.Jammed;
                    o.Collide(elapsedTime);
                    GameProperties.Vibrate(0.05);
                }
            }

        }

        public void Stop()
        {
            _zipper.Stop();
            foreach (Obstacle o in _obstacles)
            {
                o.Stop();
            }
        }
        #endregion

        #region Destroy
        public void Destroy()
        {
            foreach (Obstacle g in _obstacles)
            {
                g.Destroy();
            }

            _obstacles.RemoveRange(0, _obstacles.Count);
            _targetTimes.RemoveRange(0, _targetTimes.Count);

            _zipper.Destroy();
            SpriteManager.RemoveSprite(_background);
            _background = null;
        }

        private void PartialDestroy()
        {
            foreach (Obstacle g in _obstacles)
            {
                g.Destroy();
            }

            _obstacles.RemoveRange(0, _obstacles.Count);

            _zipper.Destroy();
            _zipper = null;
        }

        #endregion

        #region Static
        /// <summary>
        /// Gets the level description, the title and the times of a selected level
        /// in a pipe delimited format.
        /// </summary>
        public static string GetLevelBoxInfo(int worldNumber, int levelNumber)
        {
            string path = GetLevelPath(worldNumber, levelNumber);

            StreamReader read = new StreamReader(TitleContainer.OpenStream(path));
            StringBuilder s = new StringBuilder();

            while (!read.EndOfStream)
            {
                string line = read.ReadLine();
                string[] split = line.Split(' ');
                if (split[0].Equals("ln") || split[0].Equals("ld"))
                {
                    s.Append(line.Substring(3));
                    s.Append("|");
                }
                else if (split[0].Equals("t"))
                {
                    s.Append(split[2]);
                    if (!split[1].Equals("b"))
                    {
                        s.Append("|");
                    }
                    else
                    {
                        break;
                    }
                }
            }

            read.Close();

            return s.ToString(0, s.Length);
        }

        #endregion

        #region Reset

        public void Reset()
        {
            FadeOut();
            Restarting = true;
        }

        public void Reload()
        {
            Destroy();
            LoadLevel();
            Restarting = false;
        }

        public void FadeOut()
        {
            foreach (Obstacle o in _obstacles)
            {
                o.FadeOut();
            }
            _zipper.FadeOut();
        }

        public virtual void PartialFadeOut()
        {
            foreach (Obstacle o in _obstacles)
            {
                o.PartialFadeOut();
            }
            _zipper.PartialFadeOut();
        }

        public virtual void FadeIn()
        {
            foreach (Obstacle o in _obstacles)
            {
                o.FadeIn();
            }
            _zipper.FadeIn();
        }

        public virtual bool DoneFading()
        {
            foreach (Obstacle o in _obstacles)
            {
                o.DoneFading();
            }
            return _zipper.DoneFading();
        }

        public virtual void QuickFadeIn()
        {
            _zipper.QuickFadeIn();
        }

        #endregion

        #region Private Methods

        #region Load Path
        private static string GetLevelPath(int worldNum, int levelNum)
        {
            return @"Content\Levels\" + worldNum + @"\" + levelNum + ".xlvl";
        }

        #endregion

        private void SetBG(int bgNum)
        {
            if (_background == null)
            {
                _background = SpriteManager.AddSprite(@"Content\Backgrounds\bg" + bgNum, "Global");
                _background.Z = -0.1f;
                _background.PixelScale();
            }
        }

        #endregion

        #endregion

    }
}
